package com.fastjars.business.shiro.session;

import com.fastjars.business.shiro.model.UserOnline;
import com.fastjars.business.shiro.model.UserModel;
import com.fastjars.business.spring.ContextHolder;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * SessionManager
 * 自定义Session 方法扩展
 * @author Brant Liu <br> 邮箱：<br>lbf1988@qq.com <br>日期：<br>2017/12/24
 * @version 1.0.0
 */
public class SessionManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(SessionManager.class);

    public static final String DEFAULT_SESSION_STATUS = "session-online-status";

    private SessionDAO sessionDAO;

    public static SessionManager me(){
        return ContextHolder.getBean(SessionManager.class);
    }

    /**
     * 获取所有的有效Session用户
     * @return
     */
    public List<UserOnline> getOnlineUser(){
        //获取所有session
        Collection<Session> sessions = sessionDAO.getActiveSessions();
        List<UserOnline> list = new ArrayList<UserOnline>();
        for (Session session : sessions) {
            UserOnline userOnline = getSessionUserOnline(session);
            if(null != userOnline){
                list.add(userOnline);
            }
        }
        return list;
    }

    /**
     * 根据会话sessionId获取用户信息
     * @param sessionId
     * @return
     */
    public UserOnline getSession(String sessionId){
        Session session = sessionDAO.readSession(sessionId);
        return getSessionUserOnline(session);
    }

    /**
     * 改变Session在线状态
     * @param status
     * @param sessionIds
     */
    public void changeSessionStatus(Byte status, String sessionIds) {
        try {
            String[] sessionIdArray = null;
            if(sessionIds.indexOf(",") ==-1){
                sessionIdArray = new String[]{sessionIds};
            }else{
                sessionIdArray = sessionIds.split(",");
            }
            for (String id : sessionIdArray) {
                Session session = sessionDAO.readSession(id);
                SessionStatus sessionStatus = new SessionStatus();
                sessionStatus.setOnlineStatus(status);
                session.setAttribute(DEFAULT_SESSION_STATUS, sessionStatus);
                sessionDAO.update(session);
            }
        } catch (Exception e) {
            LOGGER.error("改变Session状态错误，sessionId[%s]", sessionIds);
        }
    }

    /**
     * 禁用的用户
     * @param id		用户ID
     * @param status	用户状态
     */
    public void changeUserById(Long id, Byte status) {
        //获取所有在线用户
        for(UserOnline online : getOnlineUser()){
            Long userId = online.getId();
            //匹配用户ID
            if(userId.equals(id)){
                //获取用户Session
                Session session = sessionDAO.readSession(online.getSessionId());
                //标记用户Session
                SessionStatus sessionStatus = (SessionStatus) session.getAttribute(DEFAULT_SESSION_STATUS);
                //是否踢出 true:有效，false：踢出。
                sessionStatus.setOnlineStatus(status);
                //更新Session
                sessionDAO.update(session);
            }
        }
    }

    /**
     * 根据会话获取用户信息
     * @param session
     * @return
     */
    private UserOnline getSessionUserOnline(Session session){
        Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
        if(null==obj){
            return null;
        }
        if(obj instanceof SimplePrincipalCollection){
            SimplePrincipalCollection spc = (SimplePrincipalCollection)obj;
            /**
             * 获取用户登录的，@link SampleRealm.doGetAuthenticationInfo(...)方法中
             * return new SimpleAuthenticationInfo(user,user.getPswd(), getName());的user 对象。
             */
            obj = spc.getPrimaryPrincipal();
            if(null != obj && obj instanceof UserModel){
                UserOnline online = new UserOnline((UserModel)obj);
                online.setLastAccess(session.getLastAccessTime());
                online.setHost(session.getHost());
                online.setSessionId(session.getId().toString());
                online.setLastAccess(session.getLastAccessTime());
                online.setTimeout(session.getTimeout());
                online.setStartTime(session.getStartTimestamp());
                SessionStatus sessionStatus = (SessionStatus) session.getAttribute(DEFAULT_SESSION_STATUS);
                online.setSessionStatus(sessionStatus.getOnlineStatus());
                return online;
            }
        }
        return null;
    }

    public Set<?> toSet(Object[] array){
        Set<Object> set = new TreeSet<>();
        for(Object id : array){
            set.add(id);
        }
        return set;
    }

    /**
     * 根据ID查询 SimplePrincipalCollection
     * @param userIds 用户ID
     * @return
     */
    public List<SimplePrincipalCollection> getSimplePrincipalCollectionByUserId(Long... userIds){
        //把userIds 转成Set，好判断
        Set<Long> idset = (Set<Long>) toSet(userIds);
        //获取所有session
        Collection<Session> sessions = sessionDAO.getActiveSessions();
        //定义返回
        List<SimplePrincipalCollection> list = new ArrayList<SimplePrincipalCollection>();
        for (Session session : sessions) {
            //获取SimplePrincipalCollection
            Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            if(null != obj && obj instanceof SimplePrincipalCollection){
                //强转
                SimplePrincipalCollection spc = (SimplePrincipalCollection)obj;
                //判断用户，匹配用户ID。
                obj = spc.getPrimaryPrincipal();
                if(null != obj && obj instanceof UserModel){
                    UserModel user = (UserModel)obj;
                    //比较用户ID，符合即加入集合
                    if(null != user && idset.contains(user.getId())){
                        list.add(spc);
                    }
                }
            }
        }
        return list;
    }

    public void setSessionDAO(SessionDAO sessionDAO) {
        this.sessionDAO = sessionDAO;
    }
}
